package main

import (
	"context"
	"flag"
	"github.com/chicken-team-outside/chicken_transmission/client_core"
	"github.com/chicken-team-outside/chicken_transmission/logger"
	"github.com/chicken-team-outside/chicken_transmission/nas_server/api"
	ginzap "github.com/gin-contrib/zap"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"os"
	"path/filepath"
)

var dataDirPath = flag.String("d", getExecutableDir(), "data storage directory")
var logLevel = flag.String("L", "error", "log level[debug, info, warn, error]")
var serverAddress = flag.String("l", "0.0.0.0:8080", "address to listen on server")
var engin = gin.New()

func getExecutableDir() string {
	executablePath, err := os.Executable()
	if err != nil {
		zap.L().Fatal("Cannot get the path to the executable file, try specifying the data storage directory", zap.Error(err))
		return ""
	} else {
		return filepath.Dir(executablePath)
	}
}

func checkAndCreateDatabaseDir() bool {
	stat, err := os.Stat(*dataDirPath)
	if err != nil {
		if os.IsNotExist(err) {
			err = os.MkdirAll(*dataDirPath, os.ModeDir)
			if err != nil {
				zap.L().Fatal("Can't create data storage directory, try specifying the data storage directory", zap.String("path", *dataDirPath), zap.Error(err))
			}
		} else {
			zap.L().Fatal("Unable to get data storage path status, try specifying the data storage directory", zap.String("path", *dataDirPath), zap.Error(err))
		}
	} else if !stat.IsDir() {
		zap.L().Fatal("data storage path is not a directory, try specifying the data storage directory", zap.String("path", *dataDirPath), zap.Error(err))
		return false
	}
	return true
}

func initLog() bool {
	l := zapcore.DebugLevel
	err := l.UnmarshalText([]byte(*logLevel))
	if err != nil {
		zap.L().Fatal("invalid log level value", zap.String("value", *logLevel), zap.Error(err))
	} else {
		logger.SetLogLevel(l)
	}
	return err == nil
}

func initClientCore(ctx context.Context) bool {
	databaseFilePath := filepath.Join(*dataDirPath, "data")
	err := client_core.Init(ctx, databaseFilePath, engin)
	if err != nil {
		zap.L().Fatal("Failed to initialize engine", zap.String("database", *dataDirPath), zap.Error(err))
	}
	return err == nil
}

func startEngine() bool {
	err := engin.Run(*serverAddress)
	if err != nil {
		zap.L().Fatal("Failed to run http server", zap.String("address", *serverAddress), zap.Error(err))
	}
	return err == nil
}

func main() {
	flag.Parse()
	ret := initLog()
	if ret {
		ret = checkAndCreateDatabaseDir()
	}
	engin.Use(ginzap.RecoveryWithZap(zap.L(), true))
	if ret {
		ret = initClientCore(context.Background())
	}
	api.Init(engin.Group("/api"))
	if ret {
		ret = startEngine()
	}
	if !ret {
		flag.Usage()
	}
}
